/*
 *  Copyright (C) 2010 Glauco
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.balisunrise.application;

import java.util.HashMap;
import java.util.logging.Level;
import org.balisunrise.common.DAO;
import org.balisunrise.common.VisualEntity;

/**
 * Esta classe é controlador de instâncias de DAO.
 * Existe uma instância global de DAO que pode ser acessado por todos os objetos
 * e existem instâncias específicas para cada VisualEntity que existir.
 * <br>
 * Lembra-te: Só existirá um DAO para um VisualEntity cuja o Owner não seja
 * outro VisualEntity.
 *
 * @author glauco
 */
public class DAOManager {

    /**
     * Chave padrão para o Mapa de DAO.
     */
    private static final String daoKey = "DAO";

    /**
     * Mapa de Classes DAO.
     */
    private HashMap<String,Class<? extends DAO>> daoMap;

    /**
     * Instância dos DAO.
     */
    private HashMap<VisualEntity,DAO> instaceMap;

    /**
     * Instância padrão de DAO para objetos que não são um VisualEntity.
     */
    private DAO defaultDAO;

    /**
     * Construtor padrão.
     * Le o Mapa de DAO.
     * Le o DAO padrão
     */
    public DAOManager() { 
        daoMap = new HashMap<String,Class<? extends DAO>>();
        instaceMap = new HashMap<VisualEntity, DAO>();
    }

    public void putDAO(String className, Class<? extends DAO> dao){
        daoMap.put(className, dao);
    }

    /**
     * Retorna uma nova instância do objeto do interface DAO padrão.
     * O DAO padrão é utilizado por classes sem um DAO específico implementado
     * para elas.
     *
     * @return Retorna uma nova instâcia de DAO. Se nenhum dao padrão foi
     * adicionado na inicialização, retornará <code>null</code>.
     */
    public DAO getDAO(){
        try{

            if (defaultDAO == null){
                Class daoClass = daoMap.get(daoKey);
                defaultDAO = (DAO) daoClass.newInstance();
            }
            return defaultDAO;
            
        }catch(Exception ex){
            Application.get().getLogger().log(Level.SEVERE,
                    "Erro ao criar DAO padrão: " + ex.getMessage(), ex);
        }
        return null;
    }

    /**
     * Retorna uma nova instância do objeto da interface DAO específico para
     * a classe da entidade de VisualEntity.
     * Caso a classe não tenha um DAO específico é retornado o DAO padrão.
     * Caso exista uma instância para o VisualEntity, é retornado a instância
     * já criada.
     *
     * @param visualEntity VisualEntity para o DAO específico.
     * @return Retorna uma nova instâcia de DAO específico para a classe.
     * Se nenhum exitir DAO específico retorna o DAO padrão, e ainda se nenhum
     * dao padrão foi adicionado na inicialização, retornará <code>null</code>.
     */
    public DAO getDAO(VisualEntity visualEntity){

        if(instaceMap.containsKey(visualEntity)){
            return instaceMap.get(visualEntity);
        }

        DAO dao = null;
        String className = visualEntity.getEntityClass().getName();

        try{
            if(daoMap.containsKey(className)){
                Class daoClass = daoMap.get(className);
                dao = (DAO) daoClass.newInstance();
            } else
                dao = getDAO();
            instaceMap.put(visualEntity, dao);
        }catch(Exception ex){
            Application.get().getLogger().log(Level.SEVERE,
                    "Erro ao criar DAO específico para a classe " +
                    className + ": " + ex.getMessage(), ex);
        }

        return dao;
    }

    /**
     * Revome a instância de DAO para o VisualEntity.
     *
     * @param visualEntity chave da instância de DAO.
     */
    public void removeDAO(VisualEntity visualEntity){

        if(instaceMap.containsKey(visualEntity)){
            instaceMap.remove(visualEntity);
        }
    }
}
